package com.suse.service.admin.edu.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.suse.common.config.response.ApiException;
import com.suse.common.config.response.R;
import com.suse.common.util.core.StringUtil;
import com.suse.service.admin.edu.feign.CosService;
import com.suse.service.admin.edu.mapper.CourseMapper;
import com.suse.service.admin.edu.model.entity.*;
import com.suse.service.admin.edu.model.param.CourseQueryQueryParam;
import com.suse.service.admin.edu.model.param.CourseSaveParam;
import com.suse.service.admin.edu.model.param.CourseUpdateParam;
import com.suse.service.admin.edu.model.vo.CourseInfoVo;
import com.suse.service.admin.edu.model.vo.CoursePublishInfoVo;
import com.suse.service.admin.edu.model.vo.TableCourseVo;
import com.suse.service.admin.edu.service.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;

import java.util.List;

import static com.suse.common.config.response.SimpleCode.SAVE_ERROR;
import static com.suse.common.config.response.SimpleCode.UPDATE_ERROR;


/**
 * <p>
 * 课程 服务实现类
 * </p>
 *
 * @author 辜玉彬
 * @since 2022-08-11
 */
@Service
public class CourseServiceImpl extends ServiceImpl<CourseMapper, Course> implements CourseService {

    @Resource
    private CourseDescriptionService courseDescriptionService;

    @Resource
    private ChapterService chapterService;

    @Resource
    private CourseMapper courseMapper;

    @Resource
    private VideoService videoService;

    @Resource
    private CommentService commentService;

    @Resource
    private CourseCollectService courseCollectService;

    @Resource
    private CosService cosService;

    @Transactional
    @Override
    public R saveCourse(CourseSaveParam courseSaveParam) {
        String description = courseSaveParam.getDescription();
        Course course = BeanUtil.copyProperties(courseSaveParam, Course.class);
        CourseDescription courseDescription = new CourseDescription();
        courseDescription.setDescription(description);
        // 判断添加课程是否成功
        if (!save(course)) {
            throw new ApiException(SAVE_ERROR);
        }
        // 添加成功之后 MP 会自动给实体类 ID 赋值
        // 将课程 ID 赋值给课程简介 ID
        courseDescription.setId(course.getId());
        // 判断添加课程简介是否成功
        if (!courseDescriptionService.save(courseDescription)) {
            throw new ApiException(SAVE_ERROR);
        }
        return R.put("id",course.getId()).success("课程信息已保存");
    }

    @Override
    public R getCourseInfoById(String id) {
        Course course = lambdaQuery()
                .select(Course::getId,
                        Course::getTitle,
                        Course::getTeacherId,
                        Course::getFirstSubjectId,
                        Course::getSecondSubjectId,
                        Course::getLessonNum,
                        Course::getBuyCount,
                        Course::getCover,
                        Course::getPrice,
                        Course::getStep)
                .eq(Course::getId, id)
                .one();
        if (ObjectUtil.isNull(course)) {
            throw new ApiException("课程不存在！");
        }
        CourseInfoVo courseInfoVo = BeanUtil.copyProperties(course, CourseInfoVo.class);
        CourseDescription courseDescription = courseDescriptionService.lambdaQuery()
                .select(CourseDescription::getDescription)
                .eq(CourseDescription::getId, course.getId()).one();
        courseInfoVo.setDescription(courseDescription.getDescription());
        return R.success(courseInfoVo);
    }

    @Transactional
    @Override
    public R updateCourse(CourseUpdateParam courseUpdateParam) {
        String id = courseUpdateParam.getId();
        String description = courseUpdateParam.getDescription();
        Course course = BeanUtil.copyProperties(courseUpdateParam, Course.class);
        CourseDescription courseDescription = new CourseDescription();
        courseDescription.setId(id);
        courseDescription.setDescription(description);
        // 判断课程和课程简介的修改是否都成功
        if (updateById(course) && courseDescriptionService.updateById(courseDescription)) {
            return R.success("课程信息已修改");
        }else {
            throw new ApiException(UPDATE_ERROR);
        }
    }

    @Override
    public R getCourseStep(String id) {
        Course course = lambdaQuery().select(Course::getStep).eq(Course::getId, id).one();
        return R.put("step",course.getStatus()).success();
    }

    @Override
    public R getCourseTable(CourseQueryQueryParam courseQueryParam) {
        Long current = courseQueryParam.getCurrent();
        Long size = courseQueryParam.getSize();
        Page<TableCourseVo> page = new Page<>(current,size);
        page = courseMapper.getCourseTableList(courseQueryParam,page);
        long total = page.getTotal();
        List<TableCourseVo> records = page.getRecords();
        return R.put("total",total).put("records",records).success();
    }

    /**
     * 数据库外键约束
     *      互联网分布式项目中数据库不建议使用外键与级联，一切涉及级联的操作不要依赖数据库，在应用层解决
     *
     * 业务层解决级联删除
     *      先删子结点表的数据，再删父结点表的数据
     * @param id ID
     * @return R
     */
    @Transactional
    @Override
    public R removeCourseById(String id) {
        // 删除课程封面
        removeCourseCover(id);
        // 删除课程描述
        removeCourseDescription(id);
        // 删除课程收藏
        removeCourseCollect(id);
        // 删除课程评论
        removeCourseComment(id);
        // 删除课程视频
        removeCourseVideo(id);
        // 删除课程章节
        removeCourseChapter(id);
        // 删除课程
        if (removeById(id)) {
            return R.success("删除成功");
        }else {
            throw new ApiException("删除失败！");
        }
    }

    @Override
    public R getCoursePublishInfoById(String id) {
        CoursePublishInfoVo coursePublishInfoVo = courseMapper.getCoursePublishInfoById(id);
        return R.success(coursePublishInfoVo);
    }

    @Transactional
    @Override
    public R publishCourseById(String id) {
        int row = courseMapper.publishCourseById(id);
        if (row == 1) {
            return R.success("发布成功");
        }else {
            throw new ApiException("发布失败！");
        }
    }

    /**
     * 删除课程封面
     * @param id ID
     * @return 是否成功
     */
    private boolean removeCourseCover(String id) {
        Course course = getById(id);
        if (ObjectUtil.isNull(course)) {
            return false;
        }
        String cover = course.getCover();
        if (StringUtil.isEmpty(cover)) {
            return false;
        }
        R r = cosService.removeFile(cover);
        return r.getCode() == 200;
    }

    /**
     * 删除课程描述
     * @param id ID
     * @return 是否成功
     */
    private boolean removeCourseDescription(String id) {
        return courseDescriptionService.removeById(id);
    }

    /**
     * 删除课程收藏
     * @param courseId 课程ID
     * @return 是否成功
     */
    private boolean removeCourseCollect(String courseId) {
        return courseCollectService.lambdaUpdate()
                .eq(CourseCollect::getCourseId, courseId)
                .remove();
    }

    /**
     * 删除课程评论
     * @param courseId 课程ID
     * @return 是否成功
     */
    private boolean removeCourseComment(String courseId) {
        return commentService.lambdaUpdate()
                .eq(Comment::getCourseId, courseId)
                .remove();
    }

    /**
     * 删除课程视频
     * @param courseId 课程ID
     * @return 是否成功
     */
    private boolean removeCourseVideo(String courseId) {
        return videoService.lambdaUpdate()
                .eq(Video::getCourseId, courseId)
                .remove();
    }

    /**
     * 删除课程章节
     * @param courseId 课程ID
     * @return 是否成功
     */
    private boolean removeCourseChapter(String courseId) {
        return chapterService.lambdaUpdate()
                .eq(Chapter::getCourseId, courseId)
                .remove();
    }


}
